package cn.slipi.common.utils;


import java.lang.reflect.Field;
import java.util.*;

/**
 * 通用工具类之按对象中某属性排序
 *
 * @author lee
 */
public class ListUtil {
    public static final String DESC = "desc";
    public static final String ASC = "asc";

    /**
     * 对list中的元素按升序排列.
     *
     * @param list  排序集合
     * @param field 排序字段
     * @return
     */
    public static List<?> sort(List<?> list, final String field) {
        return sort(list, field, null);
    }

    /**
     * 对list中的元素进行排序.
     *
     * @param list  排序集合
     * @param field 排序字段
     * @param sort  排序方式: ListUtil.DESC(降序) ListUtil.ASC(升序).
     * @return
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static List<?> sort(List<?> list, final String field,
                               final String sort) {
        if (list == null || list.size() <= 0) {
            return list;
        }
        Collections.sort(list, (Comparator) (a, b) -> {
            int ret = 0;
            try {
                if (a instanceof Map) {
                    if (((Map) a).get(field) == null && ((Map) a).get(field) == null) {
                        return 0;
                    }
                    if (((Map) a).get(field) == null) {
                        return -1;
                    }
                    if (((Map) b).get(field) == null) {
                        return 1;
                    }
                    return ((Map) a).get(field).toString().compareTo(((Map) b).get(field).toString());
                }
                Field f = a.getClass().getDeclaredField(field);
                f.setAccessible(true);
                Class<?> type = f.getType();
                if (StrUtils.isEmpty(f.get(a)) && StrUtils.isEmpty(f.get(b))) {
                    return 0;
                }
                if (StrUtils.isEmpty(f.get(a))) {
                    return -1;
                }
                if (StrUtils.isEmpty(f.get(b))) {
                    return 1;
                }
                if (type == int.class) {
                    ret = ((Integer) f.getInt(a)).compareTo(f
                            .getInt(b));
                } else if (type == double.class) {
                    ret = ((Double) f.getDouble(a)).compareTo(f
                            .getDouble(b));
                } else if (type == long.class) {
                    ret = ((Long) f.getLong(a)).compareTo(f
                            .getLong(b));
                } else if (type == float.class) {
                    ret = ((Float) f.getFloat(a)).compareTo(f
                            .getFloat(b));
                } else if (type == Date.class) {
                    ret = ((Date) f.get(a)).compareTo((Date) f.get(b));
                } else if (isImplementsOf(type, Comparable.class)) {
                    ret = ((Comparable) f.get(a)).compareTo(f
                            .get(b));
                } else {
                    try {
                        ret = Double.valueOf((String) f.get(a)).compareTo(
                                Double.valueOf((String) f.get(b)));
                    } catch (Exception e) {
                        ret = String.valueOf(f.get(a)).compareTo(
                                String.valueOf(f.get(b)));
                    }
                }

            } catch (SecurityException | NoSuchFieldException | IllegalAccessException | IllegalArgumentException e) {
                e.printStackTrace();
            }
            if (sort != null && sort.toLowerCase().equals(DESC)) {
                return -ret;
            } else {
                return ret;
            }

        });
        return list;
    }

    /**
     * 判断对象实现的所有接口中是否包含szInterface
     *
     * @param clazz
     * @param szInterface
     * @return
     */
    public static boolean isImplementsOf(Class<?> clazz, Class<?> szInterface) {
        boolean flag = false;

        Class<?>[] face = clazz.getInterfaces();
        for (Class<?> c : face) {
            if (c == szInterface) {
                flag = true;
            } else {
                flag = isImplementsOf(c, szInterface);
            }
        }

        if (!flag && null != clazz.getSuperclass()) {
            return isImplementsOf(clazz.getSuperclass(), szInterface);
        }

        return flag;
    }


    /**
     * 判断list是否为空
     *
     * @param list
     * @return
     */
    public static boolean isNotEmpty(List<?> list) {
        if (null != list && !list.isEmpty()) {
            return true;
        }
        return false;
    }


    public static <E> boolean isEqual(List<E> list1, List<E> list2) {
        // 两个list引用相同（包括两者都为空指针的情况）
        if (list1 == list2) {
            return true;
        }

        // 两个list都为空（包括空指针、元素个数为0）
        if (list1 == null && list2.size() == 0) {
            return true;
        }

        if (list2 == null && list1.size() == 0) {
            return true;
        }

        // 两个list元素个数不相同
        if (list1.size() != list2.size()) {
            return false;
        }

        // 两个list元素个数已经相同，再比较两者内容
        // 采用这种可以忽略list中的元素的顺序
        // 涉及到对象的比较是否相同时，确保实现了equals()方法
        if (!list1.containsAll(list2)) {
            return false;
        }

        return true;
    }


    /**
     * 将一组数据平均分成n组
     *
     * @param source 要分组的数据源
     * @param n      平均分成n组
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> averageAssign(List<T> source, int n) {
        List<List<T>> result = new ArrayList<List<T>>();
        int remainder = source.size() % n;  //(先计算出余数)
        int number = source.size() / n;  //然后是商
        int offset = 0;//偏移量
        for (int i = 0; i < n; i++) {
            List<T> value = null;
            if (remainder > 0) {
                value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                remainder--;
                offset++;
            } else {
                value = source.subList(i * number + offset, (i + 1) * number + offset);
            }
            result.add(value);
        }
        return result;
    }

    /**
     * 将一组数据固定分组，每组n个元素
     *
     * @param source 要分组的数据源
     * @param n      每组n个元素
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> fixedGrouping(List<T> source, int n) {

        if (null == source || source.size() == 0 || n <= 0)
            return null;
        List<List<T>> result = new ArrayList<List<T>>();

        int sourceSize = source.size();
        int size = (source.size() / n) + 1;
        for (int i = 0; i < size; i++) {
            List<T> subset = new ArrayList<T>();
            for (int j = i * n; j < (i + 1) * n; j++) {
                if (j < sourceSize) {
                    subset.add(source.get(j));
                }
            }
            result.add(subset);
        }
        return result;
    }


    /**
     * 将一组数据固定分组，每组n个元素
     *
     * @param source 要分组的数据源
     * @param n      每组n个元素
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> fixedGrouping2(List<T> source, int n) {

        if (null == source || source.size() == 0 || n <= 0)
            return null;
        List<List<T>> result = new ArrayList<List<T>>();
        int remainder = source.size() % n;
        int size = (source.size() / n);
        for (int i = 0; i < size; i++) {
            List<T> subset = null;
            subset = source.subList(i * n, (i + 1) * n);
            result.add(subset);
        }
        if (remainder > 0) {
            List<T> subset = null;
            subset = source.subList(size * n, size * n + remainder);
            result.add(subset);
        }
        return result;
    }

}
